#pragma once
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

class Matrix {
public:
	int rows;
	int cols;
	double scalar;
	Matrix();
	vector<double> data;
	Matrix(int rows, int cols);
	double operator()(int i, int j) const;
	double &operator()(int i, int j);
	Matrix operator+(const Matrix &B);
	Matrix operator-(const Matrix &B);
	Matrix operator-(const double &x);
	Matrix operator*(const Matrix &B);
	Matrix operator*(const double &scalar);
	Matrix operator /(const double &scalar);
	Matrix operator /(const Matrix &B);
	void swap(double &a, double &b);
	Matrix inv(Matrix A);
	Matrix identity(int i);
	Matrix tranpose(const Matrix &A);
};
class FunctionScott {
public:
  virtual double f(double x)=0;
  double D(double x, double h);
};

class Markowitz : public Matrix {
	vector<double> portWeight;
	double portReturn;
	double portRisk;
public:
	Markowitz();
	void compute_markowitz(Matrix R, Matrix C, double rf);
	Matrix optimized_portfolio_wts();
	double optimized_portfolio_rtn();
	double optimized_portfolio_risk();
};
class Condition_Number : public FunctionScott {
public:
	double matrix_cn(const Matrix &A);
	double f(double x);//this i will just use to test cond
	double func_cn(double x);
};

//non class member functions
Matrix cholesky(const Matrix &A);

bool is_almost_symmetric(const Matrix &A);
bool is_almost_zero(const Matrix &A);
bool is_positive_definite(const Matrix &A);

double norm(const vector<double> &x);//norm
double norm(const Matrix &A);//norm
double norm(const double &x);//norm

ostream &operator<<(ostream &out, const Matrix& A);
Matrix operator/(const double &scalar, Matrix A);//gauss jordan

//Test Functions
void matrixOperationsTest();
void normTest();
void symmetricZeroTest();
void conditionNumTest();
void choleskyTest();
void positiveDefinite();
void markowtizTest();

#pragma once 
#include "iostream"
#include "string"
#include "cmath"
#include "vector"
#include "Numeric.h"
#include <iostream> 
using namespace std;

class function: public Matrix{

public:
  function();
  
  virtual double f(double x)=0;
  
  double Df(double x, double h=0.00001);

  double DDf(double x, double h=1e-5);
  
  Matrix fit_least_squares(const std::vector<std::vector<double> >& points,const std::vector<double (*)(double)>& f, double& chi2);
  
  Matrix exp(const Matrix &A, double ap=1e-6, double rp=1e-4, double ns=40);
  
  double solve_bisection(double a, double b, double ap=1e-6, double rp=1e-4, double ns=100);
  
  double solve_newton(double x_guess, double ap=1e-6, double rp=1e-4, double ns=20);
  
  double solve_newton_stabilized(double a, double b, double ap=1e-6, double rp=1e-4, double ns=20);
 
  double optimize_bisection(double a, double b, double ap=1e-6, double rp=1e-4, double ns=100);
  
  double optimize_newton(double x_guess, double ap=1e-6, double rp=1e-4, double ns=20);
   
};

  void test_bisection();

  void test_newton();

  void test_newton_stabilized();

  void test_optimize_bisection();

  void test_optimize_newton();